// 版权所有2009 Go作者。保留所有权利。
// 此源代码的使用受BSD样式
// 许可证的约束，该许可证可以在许可证文件中找到。

package runtime

import (
	"internal/abi"
	"internal/goarch"
	"runtime/internal/atomic"
	"unsafe"
)

// TODO（brainman）：不需要那些
const (
	_NSIG = 65
)

// go:cgo_import_动态运行时_AddVectoredExceptionHandler AddVectoredExceptionHandler%2“kernel32.dll”
// go:cgo_import_dynamic runtime_CloseHandle CloseHandle%1“kernel32.dll”
// go:cgo_import_动态运行时_CreateEventA CreateEventA%4“kernel32.dll”
// go:cgo_import_动态运行时_CreateFileA CreateFileA%7“kernel32.dll”
// go:cgo_import_动态运行时_CreateIoCompletionPort CreateIoCompletionPort%4“kernel32.dll”
// go:cgo_import_动态运行时_CreateThread CreateThread%6“kernel32.dll”
// go:cgo_import_动态运行时_CreateWaitableTimerA CreateWaitableTimerA%3“kernel32.dll”
// go:cgo_import_动态运行时_CreateWaitableTimerExW CreateWaitableTimerExW%4“kernel32.dll”
// go:cgo_import_dynamic runtime_DuplicateHandle DuplicateHandle%7“kernel32.dll”
// go:cgo_import_动态运行时_ExitProcess ExitProcess%1“kernel32.dll”
// go:cgo_import_动态运行时_FreeEnvironmentStringsW FreeEnvironmentStringsW%1“kernel32.dll”
// go:cgo_import_dynamic runtime_GetConsoleMode GetConsoleMode%2“kernel32.dll”
// go:cgo_import_动态运行时_GetEnvironmentStringsW GetEnvironmentStringsW%0“kernel32.dll”
// go:cgo_import_dynamic runtime_GetProcAddress GetProcAddress%2“kernel32.dll”
// go:cgo_import_动态运行时_GetProcessAffinityMask GetProcessAffinityMask%3“kernel32.dll”
// go:cgo_import_dynamic runtime_GetQueuedCompletionStatusEx GetQueuedCompletionStatusEx%6“kernel32.dll”
// go:cgo\u import\u动态运行时_GetStdHandle GetStdHandle%1“kernel32.dll”
// go:cgo_import_动态运行时_GetSystemDirectoryA GetSystemDirectoryA%2“kernel32.dll”
// go:cgo_import_动态运行时_GetSystemInfo GetSystemInfo%1“kernel32.dll”
// go:cgo_import_动态运行时_GetThreadContext GetThreadContext%2“kernel32.dll”
// go:cgo_import_动态运行时_SetThreadContext SetThreadContext%2“kernel32.dll”
// go:cgo_import_动态运行时_LoadLibraryW LoadLibraryW%1“kernel32.dll”
// go:cgo_import_dynamic runtime_LoadLibraryA LoadLibraryA%1“kernel32.dll”
// go:cgo_import_动态运行时_PostQueuedCompletionStatus PostQueuedCompletionStatus%4“kernel32.dll”
// go:cgo\u import\u动态运行时_ResumeThread ResumeThread%1“kernel32.dll”
// go:cgo_import_动态运行时_SetConsoleCtrlHandler SetConsoleCtrlHandler%2“kernel32.dll”
// go:cgo_import_动态运行时_SetErrorMode SetErrorMode%1“kernel32.dll”
// go:cgo_import_动态运行时_SetEvent SetEvent%1“kernel32.dll”
// go:cgo_import_动态运行时_SetProcessPriorityBoost SetProcessPriorityBoost%2“kernel32.dll”
// 转到：cgo\u import\u dynamic runtime_SetThreadPriority SetThreadPriority%2“kernel32.dll”
// go:cgo_import_动态运行时_SetUnhandledExceptionFilter SetUnhandledExceptionFilter%1“kernel32.dll”
// go:cgo_import_dynamic runtime_SetWaitableTimer SetWaitableTimer%6“kernel32.dll”
// go:cgo_import_动态运行时_睡眠睡眠%1“kernel32.dll”
// go:cgo_import_动态运行时_SuspendThread SuspendThread%1“kernel32.dll”
// go:cgo_import_动态运行时_SwitchToThread SwitchToThread%0“kernel32.dll”
// go:cgo_import_动态运行时_TlsAlloc TlsAlloc%0“kernel32.dll”
// go:cgo_import_动态运行时_VirtualAlloc VirtualAlloc%4“kernel32.dll”
// go:cgo_import_动态运行时_VirtualFree VirtualFree%3“kernel32.dll”
// go:cgo_import_动态运行时_VirtualQuery VirtualQuery%3“kernel32.dll”
// go:cgo_import_动态运行时_WaitForSingleObject WaitForSingleObject%2“kernel32.dll”
// go:cgo_import_动态运行时_WaitForMultipleObjects WaitForMultipleObjects%4“kernel32.dll”
// go:cgo_import_动态运行时_WriteConsoleW WriteConsoleW%5“kernel32.dll”
// go:cgo_import_动态运行时_WriteFile WriteFile%5“kernel32.dll”

type stdFunction unsafe.Pointer

var (
	// 以下系统调用在每台Windows PC上都可用。
	// 所有这些变量都是在Go程序启动之前由Windows可执行文件
	// 加载程序设置的。
	_AddVectoredExceptionHandler,
	_CloseHandle,
	_CreateEventA,
	_CreateFileA,
	_CreateIoCompletionPort,
	_CreateThread,
	_CreateWaitableTimerA,
	_CreateWaitableTimerExW,
	_DuplicateHandle,
	_ExitProcess,
	_FreeEnvironmentStringsW,
	_GetConsoleMode,
	_GetEnvironmentStringsW,
	_GetProcAddress,
	_GetProcessAffinityMask,
	_GetQueuedCompletionStatusEx,
	_GetStdHandle,
	_GetSystemDirectoryA,
	_GetSystemInfo,
	_GetSystemTimeAsFileTime,
	_GetThreadContext,
	_SetThreadContext,
	_LoadLibraryW,
	_LoadLibraryA,
	_PostQueuedCompletionStatus,
	_QueryPerformanceCounter,
	_QueryPerformanceFrequency,
	_ResumeThread,
	_SetConsoleCtrlHandler,
	_SetErrorMode,
	_SetEvent,
	_SetProcessPriorityBoost,
	_SetThreadPriority,
	_SetUnhandledExceptionFilter,
	_SetWaitableTimer,
	_Sleep,
	_SuspendThread,
	_SwitchToThread,
	_TlsAlloc,
	_VirtualAlloc,
	_VirtualFree,
	_VirtualQuery,
	_WaitForSingleObject,
	_WaitForMultipleObjects,
	_WriteConsoleW,
	_WriteFile,
	_ stdFunction

	// 以下系统调用仅在某些Windows PC上可用。
	// 我们将在使用系统调用之前加载系统调用（如果可用）。
	_AddDllDirectory,
	_AddVectoredContinueHandler,
	_LoadLibraryExA,
	_LoadLibraryExW,
	_ stdFunction

	// 使用RtlGenRandom生成加密随机数据。
	// 微软推荐了这种方法（详见
	// 15589）。
	// RtlGenRandom未在advapi32中列出。dll，而不是
	// RtlGenRandom函数可以通过搜索SystemFunction036找到。
	// 在将可执行文件构建为Cgo时，Mingw的某些版本也无法链接到SystemFunction036 
	// 。因此，在运行时启动时手动加载SystemFunction036 
	// 。
	_RtlGenRandom stdFunction

	// 加载ntdll。在启动过程中手动创建dll，否则会将错误的printf函数链接到cgo可执行文件（有关详细信息，请参阅问题
	// 12030）。
	_NtWaitForSingleObject  stdFunction
	_RtlGetCurrentPeb       stdFunction
	_RtlGetNtVersionNumbers stdFunction

	// 这些是非内核32的。dll，所以我们更喜欢加载LibraryEx。
	_timeBeginPeriod,
	_timeEndPeriod,
	_WSAGetOverlappedResult,
	_ stdFunction
)

// 由windows CreateThread调用的函数
// 启动新的os线程。
func tstart_stdcall(newm *m)

// Init time helper 
func wintls()

type mOS struct {
	threadLock mutex   // 保护“线程”并防止关闭
	thread     uintptr // 线程句柄

	waitsema   uintptr // 锁上驻车信号量
	resumesema uintptr // 指示暂停/恢复

	highResTimer uintptr // usleep 

	// preemptExtLock将preemptM与
	// 外部C代码。
	// 
	// 这可以防止调用
	// SuspendThread的preemptM和调用
	// ExitProcess的线程上的外部代码之间的争用。如果这些同时发生，则有可能退出挂起的线程并挂起退出的线程，从而导致死锁。
	// 
	// 0表示此M未被抢占或在外部
	// 代码中。输入外部代码的大小写从0到1。如果
	// 失败，说明抢占正在进行，因此线程必须等待抢占。preemptM也将这种情况从0扩展到
	// 1。如果失败，抢占将失败（就像
	// PC不在Go代码中一样）。当
	// 从外部代码返回或抢占完成后，该值重置为0。
	// 
	// TODO（奥斯汀）：如果抢占更多
	// 在G/P状态和抢占上紧密同步
	// 阻止向_Gsyscall/_Psyscall的转换，我们可能不需要这个。
	preemptExtLock uint32
}

// go:linkname os_sigos。sigpipe 
func os_sigpipe() {
	throw("too many writes on closed pipe")
}

// 存根，以便测试可以正确链接。这些永远不应该被称为。
func open(name *byte, mode, perm int32) int32 {
	throw("unimplemented")
	return -1
}
func closefd(fd int32) int32 {
	throw("unimplemented")
	return -1
}
func read(fd int32, p unsafe.Pointer, n int32) int32 {
	throw("unimplemented")
	return -1
}

type sigset struct{}

// 使用stdcall约定调用Windows函数，
// 并在调用过程中切换到操作系统堆栈。
func asmstdcall(fn unsafe.Pointer)

var asmstdcallAddr unsafe.Pointer

func windowsFindfunc(lib uintptr, name []byte) stdFunction {
	if name[len(name)-1] != 0 {
		throw("usage")
	}
	f := stdcall2(_GetProcAddress, lib, uintptr(unsafe.Pointer(&name[0])))
	return stdFunction(unsafe.Pointer(f))
}

const _MAX_PATH = 260 // https:
var sysDirectory [_MAX_PATH + 1]byte
var sysDirectoryLen uintptr

func windowsLoadSystemLib(name []byte) uintptr {
	if sysDirectoryLen == 0 {
		l := stdcall2(_GetSystemDirectoryA, uintptr(unsafe.Pointer(&sysDirectory[0])), uintptr(len(sysDirectory)-1))
		if l == 0 || l > uintptr(len(sysDirectory)-1) {
			throw("Unable to determine system directory")
		}
		sysDirectory[l] = '\\'
		sysDirectoryLen = l + 1
	}
	if useLoadLibraryEx {
		return stdcall3(_LoadLibraryExA, uintptr(unsafe.Pointer(&name[0])), 0, _LOAD_LIBRARY_SEARCH_SYSTEM32)
	} else {
		absName := append(sysDirectory[:sysDirectoryLen], name...)
		return stdcall1(_LoadLibraryA, uintptr(unsafe.Pointer(&absName[0])))
	}
}

const haveCputicksAsm = GOARCH == "386" || GOARCH == "amd64"

func loadOptionalSyscalls() {
	var kernel32dll = []byte("kernel32.dll\000")
	k32 := stdcall1(_LoadLibraryA, uintptr(unsafe.Pointer(&kernel32dll[0])))
	if k32 == 0 {
		throw("kernel32.dll not found")
	}
	_AddDllDirectory = windowsFindfunc(k32, []byte("AddDllDirectory\000"))
	_AddVectoredContinueHandler = windowsFindfunc(k32, []byte("AddVectoredContinueHandler\000"))
	_LoadLibraryExA = windowsFindfunc(k32, []byte("LoadLibraryExA\000"))
	_LoadLibraryExW = windowsFindfunc(k32, []byte("LoadLibraryExW\000"))
	useLoadLibraryEx = (_LoadLibraryExW != nil && _LoadLibraryExA != nil && _AddDllDirectory != nil)

	var advapi32dll = []byte("advapi32.dll\000")
	a32 := windowsLoadSystemLib(advapi32dll)
	if a32 == 0 {
		throw("advapi32.dll not found")
	}
	_RtlGenRandom = windowsFindfunc(a32, []byte("SystemFunction036\000"))

	var ntdll = []byte("ntdll.dll\000")
	n32 := windowsLoadSystemLib(ntdll)
	if n32 == 0 {
		throw("ntdll.dll not found")
	}
	_NtWaitForSingleObject = windowsFindfunc(n32, []byte("NtWaitForSingleObject\000"))
	_RtlGetCurrentPeb = windowsFindfunc(n32, []byte("RtlGetCurrentPeb\000"))
	_RtlGetNtVersionNumbers = windowsFindfunc(n32, []byte("RtlGetNtVersionNumbers\000"))

	if !haveCputicksAsm {
		_QueryPerformanceCounter = windowsFindfunc(k32, []byte("QueryPerformanceCounter\000"))
		if _QueryPerformanceCounter == nil {
			throw("could not find QPC syscalls")
		}
	}

	var winmmdll = []byte("winmm.dll\000")
	m32 := windowsLoadSystemLib(winmmdll)
	if m32 == 0 {
		throw("winmm.dll not found")
	}
	_timeBeginPeriod = windowsFindfunc(m32, []byte("timeBeginPeriod\000"))
	_timeEndPeriod = windowsFindfunc(m32, []byte("timeEndPeriod\000"))
	if _timeBeginPeriod == nil || _timeEndPeriod == nil {
		throw("timeBegin/EndPeriod not found")
	}

	var ws232dll = []byte("ws2_32.dll\000")
	ws232 := windowsLoadSystemLib(ws232dll)
	if ws232 == 0 {
		throw("ws2_32.dll not found")
	}
	_WSAGetOverlappedResult = windowsFindfunc(ws232, []byte("WSAGetOverlappedResult\000"))
	if _WSAGetOverlappedResult == nil {
		throw("WSAGetOverlappedResult not found")
	}

	if windowsFindfunc(n32, []byte("wine_get_version\000")) != nil {
		// 在Wine上运行
		initWine(k32)
	}
}

func monitorSuspendResume() {
	const (
		_DEVICE_NOTIFY_CALLBACK = 2
	)
	type _DEVICE_NOTIFY_SUBSCRIBE_PARAMETERS struct {
		callback uintptr
		context  uintptr
	}

	powrprof := windowsLoadSystemLib([]byte("powrprof.dll\000"))
	if powrprof == 0 {
		return // 在Windows 7上运行，我们无论如何都不需要它。
	}
	powerRegisterSuspendResumeNotification := windowsFindfunc(powrprof, []byte("PowerRegisterSuspendResumeNotification\000"))
	if powerRegisterSuspendResumeNotification == nil {
		return // 运行在Windows 7上，在Windows 7上我们根本不需要它。go:nosplit 
	}
	var fn any = func(context uintptr, changeType uint32, setting uintptr) uintptr {
		for mp := (*m)(atomic.Loadp(unsafe.Pointer(&allm))); mp != nil; mp = mp.alllink {
			if mp.resumesema != 0 {
				stdcall1(_SetEvent, mp.resumesema)
			}
		}
		return 0
	}
	params := _DEVICE_NOTIFY_SUBSCRIBE_PARAMETERS{
		callback: compileCallback(*efaceOf(&fn), true),
	}
	handle := uintptr(0)
	stdcall3(powerRegisterSuspendResumeNotification, _DEVICE_NOTIFY_CALLBACK,
		uintptr(unsafe.Pointer(&params)), uintptr(unsafe.Pointer(&handle)))
}

// go:nosplit 
func getLoadLibrary() uintptr {
	return uintptr(unsafe.Pointer(_LoadLibraryW))
}

// go:nosplit 
func getLoadLibraryEx() uintptr {
	return uintptr(unsafe.Pointer(_LoadLibraryExW))
}

// go:nosplit 
func getGetProcAddress() uintptr {
	return uintptr(unsafe.Pointer(_GetProcAddress))
}

func getproccount() int32 {
	var mask, sysmask uintptr
	ret := stdcall3(_GetProcessAffinityMask, currentProcess, uintptr(unsafe.Pointer(&mask)), uintptr(unsafe.Pointer(&sysmask)))
	if ret != 0 {
		n := 0
		maskbits := int(unsafe.Sizeof(mask) * 8)
		for i := 0; i < maskbits; i++ {
			if mask&(1<<uint(i)) != 0 {
				n++
			}
		}
		if n != 0 {
			return int32(n)
		}
	}
	// /如果GetProcessAffinityMask失败，请使用GetSystemInfo。s和sys_windows_amd64。s:
	var info systeminfo
	stdcall1(_GetSystemInfo, uintptr(unsafe.Pointer(&info)))
	return int32(info.dwnumberofprocessors)
}

func getPageSize() uintptr {
	var info systeminfo
	stdcall1(_GetSystemInfo, uintptr(unsafe.Pointer(&info)))
	return uintptr(info.dwpagesize)
}

const (
)

func getlasterror() uint32

// 加载DLL时，我们更喜欢使用带有
// 加载库搜索标志（如果可用）的LoadLibraryEx。不过，LoadLibraryEx在旧Windows上不可用，而LOAD_LIBRARY_SEARCH_*
// 标志在某些没有安全补丁的Windows版本上不可用。
// 
// https:
// “Windows 7、Windows Server 2008 R2、Windows Vista和Windows 
// Server 2008:在安装了KB2533623的
// 系统上可以使用LOAD_LIBRARY_SEARCH_*标志。要确定
// 标志是否可用，请使用GetProcAddress获取
// AdddDirectory、RemoveDllDirectory或SetDefaultdLLDirectory的地址。”
// 函数。如果GetProcAddress成功，LOAD_LIBRARY_SEARCH_*
// 标志可以与LoadLibraryEx一起使用。“
var useLoadLibraryEx bool

var timeBeginPeriodRetValue uint32

// osRelaxMinNS表示，如果下一个
// 计时器距离现在不到60毫秒，sysmon就不应该osRelax。由于osRelaxing可能会将
// 计时器分辨率降低到15.6毫秒，这将使计时器错误保持在大约1 
// 4中的一部分。
const osRelaxMinNS = 60 * 1e6

// osRelax在从
// 转换到
// 
// 某些版本的Windows具有高分辨率计时器。对于那些
// 版本，osRelax是noop。
// 对于没有高分辨率计时器的Windows版本，osRelax 
// 调整系统范围内的计时器分辨率。Go在运行时需要一个高分辨率定时器，如果我们已经在使用CPU，那么几乎没有额外的成本，但是如果所有的Ps都是空闲的，那么就没有高分辨率定时器需要消耗额外的能量来驱动高分辨率定时器。
func osRelax(relax bool) uint32 {
	if haveHighResTimer {
		// 如果高分辨率计时器可用，运行时将使用计时器
		// 短时间睡眠。这意味着不需要调整
		// 全局时钟频率。
		return 0
	}

	if relax {
		return uint32(stdcall1(_timeEndPeriod, 1))
	} else {
		return uint32(stdcall1(_timeBeginPeriod, 1))
	}
}

// haveHighResTimer表示CreateWaitableTimerEx 
// CREATE_WAITABLE_TIMER_HIGH_RESOLUTION标志可用。
var haveHighResTimer = false

// createHighResTimer使用
// CREATE_WAITABLE_TIMER_HIGH_RESOLUTION标志调用CreateWaitable Timerex以创建高
// RESOLUTION TIMER。如果CreateWaitableTimerEx失败，createHighResTimer返回新的计时器
// 句柄或0。
func createHighResTimer() uintptr {
	const (
		// 根据@jstarks，请参阅
		// https:
		_CREATE_WAITABLE_TIMER_HIGH_RESOLUTION = 0x00000002

		_SYNCHRONIZE        = 0x00100000
		_TIMER_QUERY_STATE  = 0x0001
		_TIMER_MODIFY_STATE = 0x0002
	)
	return stdcall4(_CreateWaitableTimerExW, 0, 0,
		_CREATE_WAITABLE_TIMER_HIGH_RESOLUTION,
		_SYNCHRONIZE|_TIMER_QUERY_STATE|_TIMER_MODIFY_STATE)
}

const highResTimerSupported = GOARCH == "386" || GOARCH == "amd64"

func initHighResTimer() {
	if !highResTimerSupported {
		// TODO:尚未实现。
		return
	}
	h := createHighResTimer()
	if h != 0 {
		haveHighResTimer = true
		stdcall1(_CloseHandle, h)
	}
}

// go:linkname可以使用长路径操作系统。canUseLongPaths 
var canUseLongPaths bool

// 我们希望它足够大，可以容纳sysDirectory的内容，*plus*
// 一个斜杠和另一个本身大于MAX_PATH的组件。
var longFileName [(_MAX_PATH+1)*2 + 1]byte

// initLongPathSupport初始化canUseLongPaths变量，该变量是链接到操作系统的
// 变量。可以使用长路径来确定是否需要修复长路径
// 。在最好的情况下，此函数在更新的
// Windows 10版本上运行，该版本有一个名为
// “IsLongPathAwareProcess”的PEB字段成员设置好后，我们不需要通过
// 容易出错的修复函数来访问长路径。因此，这个init 
// 函数首先检查Windows版本号，设置标志，然后
// 测试它是否实际工作。如果一切正常，那么
// canUseLongPaths将设置为true，稍后调用时设置为os。fixLongPath 
// 没有工作就早早回来了。
func initLongPathSupport() {
	const (
		IsLongPathAwareProcess = 0x80
		PebBitFieldOffset      = 3
		OPEN_EXISTING          = 3
		ERROR_PATH_NOT_FOUND   = 3
	)

	// 检查我们是否≥ 10.0.15063. 
	var maj, min, build uint32
	stdcall3(_RtlGetNtVersionNumbers, uintptr(unsafe.Pointer(&maj)), uintptr(unsafe.Pointer(&min)), uintptr(unsafe.Pointer(&build)))
	if maj < 10 || (maj == 10 && min == 0 && build&0xffff < 15063) {
		return
	}

	// 设置PEB位字段的ISLONGPATHAWAREPRESS标志。
	bitField := (*byte)(unsafe.Pointer(stdcall0(_RtlGetCurrentPeb) + PebBitFieldOffset))
	originalBitField := *bitField
	*bitField |= IsLongPathAwareProcess

	// 通过构建一个大文件
	// 路径，并查看我们是否得到错误路径，而不是
	// 其他一些错误，这表明路径太长，
	// 因此长路径支持不成功，从而检查这是否真的有效。这一部分并不是绝对必要的，但对于即将到来的
	// 中期来说，这是一个很好的有效性检查，而在
	// Windows中，这一功能仍然相对较新。
	getRandomData(longFileName[len(longFileName)-33 : len(longFileName)-1])
	start := copy(longFileName[:], sysDirectory[:sysDirectoryLen])
	const dig = "0123456789abcdef"
	for i := 0; i < 32; i++ {
		longFileName[start+i*2] = dig[longFileName[len(longFileName)-33+i]>>4]
		longFileName[start+i*2+1] = dig[longFileName[len(longFileName)-33+i]&0xf]
	}
	start += 64
	for i := start; i < len(longFileName)-1; i++ {
		longFileName[i] = 'A'
	}
	stdcall7(_CreateFileA, uintptr(unsafe.Pointer(&longFileName[0])), 0, 0, 0, OPEN_EXISTING, 0, 0)
	// 错误路径未找到错误值不同于
	// 错误文件未找到或错误名称无效，后者我们
	// 由于最后一个组件太长，在这里需要。
	if getlasterror() == ERROR_PATH_NOT_FOUND {
		*bitField = originalBitField
		println("runtime: warning: IsLongPathAwareProcess failed to enable long paths; proceeding in fixup mode")
		return
	}

	canUseLongPaths = true
}

func osinit() {
	asmstdcallAddr = unsafe.Pointer(abi.FuncPCABI0(asmstdcall))

	setBadSignalMsg()

	loadOptionalSyscalls()

	disableWER()

	initExceptionHandler()

	initHighResTimer()
	timeBeginPeriodRetValue = osRelax(false)

	initLongPathSupport()

	ncpu = getproccount()

	physPageSize = getPageSize()

	// Windows动态优先级提升假设一个进程有不同类型的专用线程
	// GUI、IO、计算等。Go进程使用
	// 等效线程，所有线程都混合执行GUI、IO、计算等。
	// 在这种上下文中，动态优先级提升只会造成伤害，所以我们将其关闭。
	stdcall2(_SetProcessPriorityBoost, currentProcess, 1)
}

// useQPCTime控制时间。现在和纳米时代使用QueryPerformanceCounter。
// 只有在葡萄酒下运行时，才将其设置为1。
var useQPCTime uint8

var qpcStartCounter int64
var qpcMultiplier int64

// go:nosplit 
func nanotimeQPC() int64 {
	var counter int64 = 0
	stdcall1(_QueryPerformanceCounter, uintptr(unsafe.Pointer(&counter)))

	// 返回纳秒数
	return (counter - qpcStartCounter) * qpcMultiplier
}

// go:nosplit 
func nowQPC() (sec int64, nsec int32, mono int64) {
	var ft int64
	stdcall1(_GetSystemTimeAsFileTime, uintptr(unsafe.Pointer(&ft)))

	t := (ft - 116444736000000000) * 100

	sec = t / 1000000000
	nsec = int32(t - sec*1000000000)

	mono = nanotimeQPC()
	return
}

func initWine(k32 uintptr) {
	_GetSystemTimeAsFileTime = windowsFindfunc(k32, []byte("GetSystemTimeAsFileTime\000"))
	if _GetSystemTimeAsFileTime == nil {
		throw("could not find GetSystemTimeAsFileTime() syscall")
	}

	_QueryPerformanceCounter = windowsFindfunc(k32, []byte("QueryPerformanceCounter\000"))
	_QueryPerformanceFrequency = windowsFindfunc(k32, []byte("QueryPerformanceFrequency\000"))
	if _QueryPerformanceCounter == nil || _QueryPerformanceFrequency == nil {
		throw("could not find QPC syscalls")
	}

	// 我们不能简单地回退到GetSystemTimeAsFileTime（）系统调用，因为它的时间不是单调的，
	// 相反，我们使用QueryPerformanceCounter系列系统调用来实现单调计时器
	// https:

	var tmp int64
	stdcall1(_QueryPerformanceFrequency, uintptr(unsafe.Pointer(&tmp)))
	if tmp == 0 {
		throw("QueryPerformanceFrequency syscall returned zero, running on unsupported hardware")
	}

	// 这不应该溢出，它是每秒性能计数器的若干个滴答声，
	// 它的分辨率最多为每使用秒10次（在葡萄酒上，在真正的硬件上甚至更小），因此这里最多为1000万次，
	// 如果溢出，请惊慌。
	if tmp > (1<<31 - 1) {
		throw("QueryPerformanceFrequency overflow 32 bit divider, check nosplit discussion to proceed")
	}
	qpcFrequency := int32(tmp)
	stdcall1(_QueryPerformanceCounter, uintptr(unsafe.Pointer(&qpcStartCounter)))

	// 因为我们应该只在Wine上运行这个时间调用，它不会失去精度，
	// 因为Wine的计时器是在10 Mhz下模拟的，所以它将是100 
	// 的一个很好的四舍五入乘法器，但是对于通用系统（比如i7上的3.3 Mhz计时器），它将不是非常精确。
	// 我们必须这样做（或类似），因为将QPC计数器乘以1亿会溢出
	// int64，结果时间将始终无效。
	qpcMultiplier = int64(timediv(1000000000, qpcFrequency, nil))

	useQPCTime = 1
}

// go:nosplit 
func getRandomData(r []byte) {
	n := 0
	if stdcall2(_RtlGenRandom, uintptr(unsafe.Pointer(&r[0])), uintptr(len(r)))&0xff != 0 {
		n = len(r)
	}
	extendRandom(r, n)
}

func goenvs() {
	// strings是指向以下形式的环境变量对的指针：
	// “envA=valA\x00envB=valB\x00\x00”（在UTF-16中）
	// /两个连续的零字节结束列表。
	strings := unsafe.Pointer(stdcall0(_GetEnvironmentStringsW))
	p := (*[1 << 24]uint16)(strings)[:]

	n := 0
	for from, i := 0, 0; true; i++ {
		if p[i] == 0 {
			// 空字符串标记结束
			if i == from {
				break
			}
			from = i + 1
			n++
		}
	}
	envs = make([]string, n)

	for i := range envs {
		envs[i] = gostringw(&p[0])
		for p[0] != 0 {
			p = p[1:]
		}
		p = p[1:] // 跳过零字节
	}

	stdcall1(_FreeEnvironmentStringsW, uintptr(strings))

	// 我们一直在这里调用这些函数，在init的后期，因此malloc为这些函数生成的回调函数工作
	// 。
	var fn any = ctrlHandler
	ctrlHandlerPC := compileCallback(*efaceOf(&fn), true)
	stdcall2(_SetConsoleCtrlHandler, ctrlHandlerPC, 1)

	monitorSuspendResume()
}

// 当进程退出时，退出设置为非零。
var exiting uint32

// go:nosplit 
func exit(code int32) {
	// 不允许线程暂停以进行抢占。否则，ExitProcess和SuspendThread可以竞争：SuspendThread 
	// 为该线程排队暂停请求，ExitProcess 
	// 杀死暂停线程，然后该线程暂停。
	lock(&suspendLock)
	atomic.Store(&exiting, 1)
	stdcall1(_ExitProcess, uintptr(code))
}

// write1必须是nosplit，因为它是在像badmorestackg0这样的函数中作为最后手段使用的。在这种情况下，我们将始终采用
// ASCII路径。
// 
// go:nosplit 
func write1(fd uintptr, buf unsafe.Pointer, n int32) int32 {
	const (
		_STD_OUTPUT_HANDLE = ^uintptr(10) // -11 
		_STD_ERROR_HANDLE  = ^uintptr(11) // -12 
	)
	var handle uintptr
	switch fd {
	case 1:
		handle = stdcall1(_GetStdHandle, _STD_OUTPUT_HANDLE)
	case 2:
		handle = stdcall1(_GetStdHandle, _STD_ERROR_HANDLE)
	default:
		// /假设fd是真正的windows句柄。
		handle = fd
	}
	isASCII := true
	b := (*[1 << 30]byte)(buf)[:n]
	for _, x := range b {
		if x >= 0x80 {
			isASCII = false
			break
		}
	}

	if !isASCII {
		var m uint32
		isConsole := stdcall2(_GetConsoleMode, handle, uintptr(unsafe.Pointer(&m))) != 0
		// 如果这是控制台输出，则可以使用各种非unicode代码页。
		// 使用专用的WriteConsole调用确保正确打印unicode。
		if isConsole {
			return int32(writeConsole(handle, buf, n))
		}
	}
	var written uint32
	stdcall5(_WriteFile, handle, uintptr(buf), uintptr(n), uintptr(unsafe.Pointer(&written)), 0)
	return int32(written)
}

var (
	utf16ConsoleBack     [1000]uint16
	utf16ConsoleBackLock mutex
)

// writeConsole将buf中的bufLen字节写入控制台文件。
// 返回写入的字节数。
func writeConsole(handle uintptr, buf unsafe.Pointer, bufLen int32) int {
	const surr2 = (surrogateMin + surrogateMax + 1) / 2

	// 不要使用延迟解锁。打印恐慌时可能会导致问题。
	lock(&utf16ConsoleBackLock)

	b := (*[1 << 30]byte)(buf)[:bufLen]
	s := *(*string)(unsafe.Pointer(&b))

	utf16tmp := utf16ConsoleBack[:]

	total := len(s)
	w := 0
	for _, r := range s {
		if w >= len(utf16tmp)-2 {
			writeConsoleUTF16(handle, utf16tmp[:w])
			w = 0
		}
		if r < 0x10000 {
			utf16tmp[w] = uint16(r)
			w++
		} else {
			r -= 0x10000
			utf16tmp[w] = surrogateMin + uint16(r>>10)&0x3ff
			utf16tmp[w+1] = surr2 + uint16(r)&0x3ff
			w += 2
		}
	}
	writeConsoleUTF16(handle, utf16tmp[:w])
	unlock(&utf16ConsoleBackLock)
	return total
}

// writeConsoleUTF16是专用的windows调用，它可以将
// 正确打印到控制台，而不考虑当前的代码页。输入为utf-16代码点。
// 句柄必须是控制台句柄。
func writeConsoleUTF16(handle uintptr, b []uint16) {
	l := uint32(len(b))
	if l == 0 {
		return
	}
	var written uint32
	stdcall5(_WriteConsoleW,
		handle,
		uintptr(unsafe.Pointer(&b[0])),
		uintptr(l),
		uintptr(unsafe.Pointer(&written)),
		0,
	)
	return
}

// go:nosplit 
func semasleep(ns int64) int32 {
	const (
		_WAIT_ABANDONED = 0x00000080
		_WAIT_OBJECT_0  = 0x00000000
		_WAIT_TIMEOUT   = 0x00000102
		_WAIT_FAILED    = 0xFFFFFFFF
	)

	var result uintptr
	if ns < 0 {
		result = stdcall2(_WaitForSingleObject, getg().m.waitsema, uintptr(_INFINITE))
	} else {
		start := nanotime()
		elapsed := int64(0)
		for {
			ms := int64(timediv(ns-elapsed, 1000000, nil))
			if ms == 0 {
				ms = 1
			}
			result = stdcall4(_WaitForMultipleObjects, 2,
				uintptr(unsafe.Pointer(&[2]uintptr{getg().m.waitsema, getg().m.resumesema})),
				0, uintptr(ms))
			if result != _WAIT_OBJECT_0+1 {
				// 不是挂起/恢复事件
				break
			}
			elapsed = nanotime() - start
			if elapsed >= ns {
				return -1
			}
		}
	}
	switch result {
	case _WAIT_OBJECT_0: // 发出信号
		return 0

	case _WAIT_TIMEOUT:
		return -1

	case _WAIT_ABANDONED:
		systemstack(func() {
			throw("runtime.semasleep wait_abandoned")
		})

	case _WAIT_FAILED:
		systemstack(func() {
			print("runtime: waitforsingleobject wait_failed; errno=", getlasterror(), "\n")
			throw("runtime.semasleep wait_failed")
		})

	default:
		systemstack(func() {
			print("runtime: waitforsingleobject unexpected; result=", result, "\n")
			throw("runtime.semasleep unexpected")
		})
	}

	return -1 // 无法访问
}

// go:nosplit 
func semawakeup(mp *m) {
	if stdcall1(_SetEvent, mp.waitsema) == 0 {
		systemstack(func() {
			print("runtime: setevent failed; errno=", getlasterror(), "\n")
			throw("runtime.semawakeup")
		})
	}
}

// go nosplit 
func semacreate(mp *m) {
	if mp.waitsema != 0 {
		return
	}
	mp.waitsema = stdcall4(_CreateEventA, 0, 0, 0, 0)
	if mp.waitsema == 0 {
		systemstack(func() {
			print("runtime: createevent failed; errno=", getlasterror(), "\n")
			throw("runtime.semacreate")
		})
	}
	mp.resumesema = stdcall4(_CreateEventA, 0, 0, 0, 0)
	if mp.resumesema == 0 {
		systemstack(func() {
			print("runtime: createevent failed; errno=", getlasterror(), "\n")
			throw("runtime.semacreate")
		})
		stdcall1(_CloseHandle, mp.waitsema)
		mp.waitsema = 0
	}
}

// 可能与m.p==nil一起运行，因此不允许写入障碍。此
// 函数由newosproc0调用，因此也需要
// 在没有堆栈保护的情况下运行。
// go:nowritebarrierrec 
// go:nosplit 
func newosproc(mp *m) {
	// 我们将堆栈大小传递为0，以使用此二进制文件的默认值。
	thandle := stdcall6(_CreateThread, 0, 0,
		abi.FuncPCABI0(tstart_stdcall), uintptr(unsafe.Pointer(mp)),
		0, 0)

	if thandle == 0 {
		if atomic.Load(&exiting) != 0 {
			// 如果与ExitProcess同时调用
			// 则CreateThread可能会失败。如果发生这种情况，只需冻结这个线程，让进程退出。见第18253期。
			lock(&deadlock)
			lock(&deadlock)
		}
		print("runtime: failed to create new OS thread (have ", mcount(), " already; errno=", getlasterror(), ")\n")
		throw("runtime.newosproc")
	}

	// 关闭thandle，以避免线程对象退出时泄漏。
	stdcall1(_CloseHandle, thandle)
}

// 由C库构建模式使用。在Linux上，这个函数将分配一个
// 堆栈，但这对于Windows不是必需的。不存在堆栈保护
// 并且GC尚未初始化，因此写屏障将失败。
// go:nowritebarrierrec 
// go:nosplit 
func newosproc0(mp *m, stk unsafe.Pointer) {
	// TODO:这是完全破坏的。传递给newosproc0（在asm_amd64.s中）
	// 的参数是stacksize和function，而不是*m和stack。
	// 检查操作系统linux。去实现一个可能真正有效的实现。
	throw("bad newosproc0")
}

func exitThread(wait *uint32) {
	// 我们不应该在Windows上访问exitThread，因为我们让操作系统清理线程。
	throw("exitThread")
}

// 调用以初始化新的m（包括引导程序m）。
// 在父线程（引导时为主线程）上调用，可以分配内存。
func mpreinit(mp *m) {
}

// go:nosplit 
func sigsave(p *sigset) {
}

// go:nosplit 
func msigrestore(sigmask sigset) {
}

// go:nosplit 
// go:nowritebarrierrec 
func clearSignalHandlers() {
}

// go:nosplit 
func sigblock(exiting bool) {
}

// 调用以初始化新m（包括引导程序m）。
// 在新线程上被调用，无法分配内存。
func minit() {
	var thandle uintptr
	if stdcall7(_DuplicateHandle, currentProcess, currentThread, currentProcess, uintptr(unsafe.Pointer(&thandle)), 0, 0, _DUPLICATE_SAME_ACCESS) == 0 {
		print("runtime.minit: duplicatehandle failed; errno=", getlasterror(), "\n")
		throw("runtime.minit: duplicatehandle failed")
	}

	mp := getg().m
	lock(&mp.threadLock)
	mp.thread = thandle

	// 如果可能，配置usleep定时器。
	if mp.highResTimer == 0 && haveHighResTimer {
		mp.highResTimer = createHighResTimer()
		if mp.highResTimer == 0 {
			print("runtime: CreateWaitableTimerEx failed; errno=", getlasterror(), "\n")
			throw("CreateWaitableTimerEx when creating timer failed")
		}
	}
	unlock(&mp.threadLock)

	// 从操作系统中查询真正的堆栈库。目前，我们正在一个小的假定堆栈上运行
	// 。
	var mbi memoryBasicInformation
	res := stdcall3(_VirtualQuery, uintptr(unsafe.Pointer(&mbi)), uintptr(unsafe.Pointer(&mbi)), unsafe.Sizeof(mbi))
	if res == 0 {
		print("runtime: VirtualQuery failed; errno=", getlasterror(), "\n")
		throw("VirtualQuery for stack base failed")
	}
	// 系统在堆栈底部留下一个8K页面保护区（理论上VirtualQuery不应该包括
	// 但它确实包含）。为
	// 调用没有堆栈检查的C函数和
	// lastcontinuehandler添加额外的8K slop。无论如何，我们都不应该接近这个
	// 边界。
	base := mbi.allocationBase + 16<<10
	// 检查堆栈边界是否正常。
	g0 := getg()
	if base > g0.stack.hi || g0.stack.hi-base > 64<<20 {
		print("runtime: g0 stack [", hex(base), ",", hex(g0.stack.hi), ")\n")
		throw("bad g0 stack")
	}
	g0.stack.lo = base
	g0.stackguard0 = g0.stack.lo + _StackGuard
	g0.stackguard1 = g0.stackguard0
	// 检查SP.
	stackcheck()
}

// 从dropm调用以撤消minit的效果。
// go:nosplit 
func unminit() {
	mp := getg().m
	lock(&mp.threadLock)
	if mp.thread != 0 {
		stdcall1(_CloseHandle, mp.thread)
		mp.thread = 0
	}
	unlock(&mp.threadLock)
}

// 从exitm调用，但不是从drop调用，以撤销线程拥有的
// minit、semacreate或其他资源的效果。打完电话后不要带锁。
// go:nosplit 
func mdestroy(mp *m) {
	if mp.highResTimer != 0 {
		stdcall1(_CloseHandle, mp.highResTimer)
		mp.highResTimer = 0
	}
	if mp.waitsema != 0 {
		stdcall1(_CloseHandle, mp.waitsema)
		mp.waitsema = 0
	}
	if mp.resumesema != 0 {
		stdcall1(_CloseHandle, mp.resumesema)
		mp.resumesema = 0
	}
}

// 在操作系统堆栈上调用stdcall。
// 可能在STW期间运行，因此不允许使用写屏障。
// go:nowritebarrier 
// go:nosplit 
func stdcall(fn stdFunction) uintptr {
	gp := getg()
	mp := gp.m
	mp.libcall.fn = uintptr(unsafe.Pointer(fn))
	resetLibcall := false
	if mp.profilehz != 0 && mp.libcallsp == 0 {
		// 将pc/sp留给cpu探查器
		mp.libcallg.set(gp)
		mp.libcallpc = getcallerpc()
		// sp必须是最后一个，因为一旦async cpu探查器发现
		// 所有三个值都非零，它将使用它们
		mp.libcallsp = getcallersp()
		resetLibcall = true // 请参阅sys_darwin中的注释。go:libcCall 
	}
	asmcgocall(asmstdcallAddr, unsafe.Pointer(&mp.libcall))
	if resetLibcall {
		mp.libcallsp = 0
	}
	return mp.libcall.r1
}

// go:nosplit 
func stdcall0(fn stdFunction) uintptr {
	mp := getg().m
	mp.libcall.n = 0
	mp.libcall.args = uintptr(noescape(unsafe.Pointer(&fn))) // 未使用，但必须为非零，在其他方面，交通事故，交通事故，交通事故，交通事故，交通事故，交通事故，交通事故，交通事故，交通事故，交通事故，交通事故，交通事故，交通事故，交通事故，交通事故，交通事故，交通事故，交通事故，交通事故，交通事故，交通事故，交通事故，交通事故，交通事故，交通事故，交通，交通，交通，交通，交通，交通，交通，交通，不安全，不安全，不安全，不安全，不安全的，不安全的，不安全的，危险的，美国的，美国的，美国的，美国的，美国的，美国的，美国的，美国的，美国的，美国的，美国的，美国的，美国的，美国的，美国的，美国的，美国的，美国的，美国的，美国的，美国的，美国的，美国的，美国的，美国的，美国的，美国的，美国的，美国的，美国的，美国的，美国的，美国的，美国的，美国的，美国的，美国的，美国的，美国的，美国的
	return stdcall(fn)
}

func stdcall1(fn stdFunction, a0 uintptr) uintptr {
	mp := getg().m
	mp.libcall.n = 1
	mp.libcall.args = uintptr(noescape(unsafe.Pointer(&a0)))
	return stdcall(fn)
}

func stdcall2(fn stdFunction, a0, a1 uintptr) uintptr {
	mp := getg().m
	mp.libcall.n = 2
	mp.libcall.args = uintptr(noescape(unsafe.Pointer(&a0)))
	return stdcall(fn)
}

func stdcall3(fn stdFunction, a0, a1, a2 uintptr) uintptr {
	mp := getg().m
	mp.libcall.n = 3
	mp.libcall.args = uintptr(noescape(unsafe.Pointer(&a0)))
	return stdcall(fn)
}

func stdcall4(fn stdFunction, a0, a1, a2, a3 uintptr) uintptr {
	mp := getg().m
	mp.libcall.n = 4
	mp.libcall.args = uintptr(noescape(unsafe.Pointer(&a0)))
	return stdcall(fn)
}

func stdcall5(fn stdFunction, a0, a1, a2, a3, a4 uintptr) uintptr {
	mp := getg().m
	mp.libcall.n = 5
	mp.libcall.args = uintptr(noescape(unsafe.Pointer(&a0)))
	return stdcall(fn)
}

// go:cgo_unsafe_args 
func stdcall6(fn stdFunction, a0, a1, a2, a3, a4, a5 uintptr) uintptr {
	mp := getg().m
	mp.libcall.n = 6
	mp.libcall.args = uintptr(noescape(unsafe.Pointer(&a0)))
	return stdcall(fn)
}

// go:nosplit 
// go:cgo_unsafe_args 
func stdcall7(fn stdFunction, a0, a1, a2, a3, a4, a5, a6 uintptr) uintptr {
	mp := getg().m
	mp.libcall.n = 7
	mp.libcall.args = uintptr(noescape(unsafe.Pointer(&a0)))
	return stdcall(fn)
}

// 这些只能在系统堆栈上运行。go:nosplit 
func usleep2(dt int32)
func usleep2HighRes(dt int32)
func switchtothread()

func osyield_no_g() {
	switchtothread()
}

func osyield() {
	systemstack(switchtothread)
}

// go:nosplit 
// go:nosplit 
func usleep_no_g(us uint32) {
	dt := -10 * int32(us) // 相对睡眠（负数），100ns单位
	usleep2(dt)
}

// go:nosplit 
func usleep(us uint32) {
	systemstack(func() {
		dt := -10 * int32(us) // 相对睡眠（负数），100ns单位
		// 如果高分辨率计时器可用且其句柄已分配给此m，请使用它。
		// 否则返回到低分辨率，它不需要手柄。
		if haveHighResTimer && getg().m.highResTimer != 0 {
			usleep2HighRes(dt)
		} else {
			usleep2(dt)
		}
	})
}

func ctrlHandler(_type uint32) uintptr {
	var s uint32

	switch _type {
	case _CTRL_C_EVENT, _CTRL_BREAK_EVENT:
		s = _SIGINT
	case _CTRL_CLOSE_EVENT, _CTRL_LOGOFF_EVENT, _CTRL_SHUTDOWN_EVENT:
		s = _SIGTERM
	default:
		return 0
	}

	if sigsend(s) {
		if s == _SIGTERM {
			// 此处理程序返回后，Windows将终止进程。
			// 无限期地阻塞以给信号处理程序一个清理的机会，
			// 但请确保首先正确地停放，以便
			// 程序的其余部分可以继续执行。
			block()
		}
		return 1
	}
	return 0
}

// 从zcallback_windows_*调用。s至系统_windows*。s 
func callbackasm1()

var profiletimer uintptr

func profilem(mp *m, thread uintptr) {
	// 将上下文与16字节对齐。
	var c *context
	var cbuf [unsafe.Sizeof(*c) + 15]byte
	c = (*context)(unsafe.Pointer((uintptr(unsafe.Pointer(&cbuf[15]))) &^ 15))

	c.contextflags = _CONTEXT_CONTROL
	stdcall2(_GetThreadContext, thread, uintptr(unsafe.Pointer(c)))

	gp := gFromSP(mp, c.sp())

	sigprof(c.ip(), c.sp(), c.lr(), gp, mp)
}

func gFromSP(mp *m, sp uintptr) *g {
	if gp := mp.g0; gp != nil && gp.stack.lo < sp && sp < gp.stack.hi {
		return gp
	}
	if gp := mp.gsignal; gp != nil && gp.stack.lo < sp && sp < gp.stack.hi {
		return gp
	}
	if gp := mp.curg; gp != nil && gp.stack.lo < sp && sp < gp.stack.hi {
		return gp
	}
	return nil
}

func profileLoop() {
	stdcall2(_SetThreadPriority, currentThread, _THREAD_PRIORITY_HIGHEST)

	for {
		stdcall2(_WaitForSingleObject, profiletimer, _INFINITE)
		first := (*m)(atomic.Loadp(unsafe.Pointer(&allm)))
		for mp := first; mp != nil; mp = mp.alllink {
			if mp == getg().m {
				// 不要描述我们自己。
				continue
			}

			lock(&mp.threadLock)
			// 不要分析Notes上阻塞的线程，
			// 这包括空闲工作线程、
			// 空闲计时器线程、空闲堆清除程序等。
			if mp.thread == 0 || mp.profilehz == 0 || mp.blocked {
				unlock(&mp.threadLock)
				continue
			}
			// 获取我们自己的线程句柄。
			var thread uintptr
			if stdcall7(_DuplicateHandle, currentProcess, mp.thread, currentProcess, uintptr(unsafe.Pointer(&thread)), 0, 0, _DUPLICATE_SAME_ACCESS) == 0 {
				print("runtime: duplicatehandle failed; errno=", getlasterror(), "\n")
				throw("duplicatehandle failed")
			}
			unlock(&mp.threadLock)

			// mp可能会在上面的DuplicateHandle 
			// 和SuspendThread之间退出。句柄
			// 将保持有效，但SuspendThread可能
			// 失败。
			if int32(stdcall1(_SuspendThread, thread)) == -1 {
				// 线程不再存在。
				stdcall1(_CloseHandle, thread)
				continue
			}
			if mp.profilehz != 0 && !mp.blocked {
				// 如果mp 
				// 正在关闭，请传递线程句柄。
				profilem(mp, thread)
			}
			stdcall1(_ResumeThread, thread)
			stdcall1(_CloseHandle, thread)
		}
	}
}

func setProcessCPUProfiler(hz int32) {
	if profiletimer == 0 {
		timer := stdcall3(_CreateWaitableTimerA, 0, 0, 0)
		atomic.Storeuintptr(&profiletimer, timer)
		newm(profileLoop, nil, -1)
	}
}

func setThreadCPUProfiler(hz int32) {
	ms := int32(0)
	due := ^int64(^uint64(1 << 63))
	if hz > 0 {
		ms = 1000 / hz
		if ms == 0 {
			ms = 1
		}
		due = int64(ms) * -10000
	}
	stdcall6(_SetWaitableTimer, profiletimer, uintptr(unsafe.Pointer(&due)), uintptr(ms), 0, 0, 0)
	atomic.Store((*uint32)(unsafe.Pointer(&getg().m.profilehz)), uint32(hz))
}

const preemptMSupported = true

// suspendLock保护同时进行的SuspendThread操作不受
// 相互挂起的影响。
var suspendLock mutex

func preemptM(mp *m) {
	if mp == getg().m {
		throw("self-preempt")
	}

	// 与可能尝试退出进程的外部代码同步。
	if !atomic.Cas(&mp.preemptExtLock, 0, 1) {
		// 外部代码正在运行。抢占
		// 尝试失败。
		atomic.Xadd(&mp.preemptGen, 1)
		return
	}

	// 获取我们自己的mp线程句柄。
	lock(&mp.threadLock)
	if mp.thread == 0 {
		// M还没有被缩小（或者只是没有被监视）。
		unlock(&mp.threadLock)
		atomic.Store(&mp.preemptExtLock, 0)
		atomic.Xadd(&mp.preemptGen, 1)
		return
	}
	var thread uintptr
	if stdcall7(_DuplicateHandle, currentProcess, mp.thread, currentProcess, uintptr(unsafe.Pointer(&thread)), 0, 0, _DUPLICATE_SAME_ACCESS) == 0 {
		print("runtime.preemptM: duplicatehandle failed; errno=", getlasterror(), "\n")
		throw("runtime.preemptM: duplicatehandle failed")
	}
	unlock(&mp.threadLock)

	// 准备线程上下文缓冲区。这必须与16字节对齐。
	var c *context
	var cbuf [unsafe.Sizeof(*c) + 15]byte
	c = (*context)(unsafe.Pointer((uintptr(unsafe.Pointer(&cbuf[15]))) &^ 15))
	c.contextflags = _CONTEXT_CONTROL

	// 序列化线程挂起。SuspendThread是异步的，
	// 所以两个线程可以分别挂起每个
	// 其他线程和死锁。我们必须在
	// GetThreadContext之后保持这个锁，因为它会一直阻塞，直到线程实际挂起。
	lock(&suspendLock)

	// 挂起线程。
	if int32(stdcall1(_SuspendThread, thread)) == -1 {
		unlock(&suspendLock)
		stdcall1(_CloseHandle, thread)
		atomic.Store(&mp.preemptExtLock, 0)
		// 线程不再存在。这不应该是
		// 可能的，只需确认请求即可。
		atomic.Xadd(&mp.preemptGen, 1)
		return
	}

	// 在这一点和一旦
	// 我们已经证明mp处于异步安全点之间，我们必须非常小心。这就像是一个信号处理器，在这个意义上，mp可以在我们停止它时做任何事情，包括持有任意的
	// 锁。

	// 在检查M 
	// 之前，我们必须获取线程上下文，因为SuspendThread只请求挂起。
	// GetThreadContext实际上会一直阻塞，直到它被挂起。
	stdcall2(_GetThreadContext, thread, uintptr(unsafe.Pointer(c)))

	unlock(&suspendLock)

	// 它想要先发制人吗？先发制人安全吗？
	gp := gFromSP(mp, c.sp())
	if gp != nil && wantAsyncPreempt(gp) {
		if ok, newpc := isAsyncSafePoint(gp, c.ip(), c.sp(), c.lr()); ok {
			// 向asyncPreempt注入调用
			targetPC := abi.FuncPCABI0(asyncPreempt)
			switch GOARCH {
			default:
				throw("unsupported architecture")
			case "386", "amd64":
				// 使其看起来像名为targetPC的线程。
				sp := c.sp()
				sp -= goarch.PtrSize
				*(*uintptr)(unsafe.Pointer(sp)) = newpc
				c.set_sp(sp)
				c.set_ip(targetPC)

			case "arm":
				// 推送LR。注入的调用负责
				// 恢复LR。gentraceback知道
				// 这个额外的插槽。见sigctxt。在
				// 信号臂中按下呼叫。go，除了我们
				// 这里从IP中减去1之外，它是类似的。
				sp := c.sp()
				sp -= goarch.PtrSize
				c.set_sp(sp)
				*(*uint32)(unsafe.Pointer(sp)) = uint32(c.lr())
				c.set_lr(newpc - 1)
				c.set_ip(targetPC)

			case "arm64":
				// 按LR键。注入的调用负责
				// 恢复LR。gentraceback知道
				// 这个额外的插槽。见sigctxt。
				// 信号_arm64。去
				sp := c.sp() - 16 // SP需要16字节对齐
				c.set_sp(sp)
				*(*uint64)(unsafe.Pointer(sp)) = uint64(c.lr())
				c.set_lr(newpc)
				c.set_ip(targetPC)
			}
			stdcall2(_SetThreadContext, thread, uintptr(unsafe.Pointer(c)))
		}
	}

	atomic.Store(&mp.preemptExtLock, 0)

	// 确认抢占。
	atomic.Xadd(&mp.preemptGen, 1)

	stdcall1(_ResumeThread, thread)
	stdcall1(_CloseHandle, thread)
}

// 在输入可能调用ExitProcess的外部代码之前调用OSPremptExtenter。
// 
// 这必须是nosplit，因为它可能是从带有
// 非类型堆栈插槽的系统调用中调用的，因此不能增长或扫描堆栈。
// 
// go:nosplit 
func osPreemptExtEnter(mp *m) {
	for !atomic.Cas(&mp.preemptExtLock, 0, 1) {
		// 正在进行异步抢占。输入外部代码是不安全的，因为它可能会调用
		// ExitProcess和SuspendThread死锁。
		// 理想情况下，我们会自己进行抢占，但
		// 不能，因为堆栈上可能有非类型化的系统调用参数
		// 。相反，只要等待并鼓励
		// SuspendThread APC运行即可。优先购买权应在短期内完成。
		osyield()
	}
	// 异步抢占现在被阻止。
}

// 从
// 可以调用ExitProcess的外部代码返回后调用OSPreemptExit。
// 
// 请参阅OSPremptExtenter了解这是nosplit的原因。
// 
// go:nosplit 
func osPreemptExtExit(mp *m) {
	atomic.Store(&mp.preemptExtLock, 0)
}
